import java.util.List
import java.util.Map
import javax.swing.*
import net.sshiffon.*
import com.jcraft.jsch.Channel

class ConnectedController {
    // these will be injected by Griffon
    def model
    def view

    def initialisedSettings=false
    def initialisedSftp=false
    def initialisedShell=false

    
    void mvcGroupInit(args) {
        model.conn = new SshiffonConnector(model.settings.user, model.settings.host,  new Integer(model.settings.port), model.settings.isKeepAlive,  new Integer(model.settings.keepAliveSeconds), new Integer(model.settings.connectionTimeout))
    }  
    
    /** 
     * Called when the document is initially opened. 
     */  
    boolean open() {
    	doLater {
    		try {

    			//connect
	            model.session = model.conn.connectSession(new SshiffonUserInfo(view.rootPanel));

	            //do tunnels
	            model.settings.tunnels?.each({if(it.enabled) { logger.info("Connecting tunnel ${it.localPort} -> ${it.remoteHost}:${it.remotePort}"); tunnel(it.localPort,it.remoteHost,it.remotePort)} })

	            //show the relevant view ...
	            logger.debug("Initial view: ${model.settings.initialView}")
	        	if('Config'.equals(model.settings.initialView))
	            {
	        		app.views.Sshiffon.configAction.closure()
	            } else if('Sftp'.equals(model.settings.initialView))
	            {
	            	app.views.Sshiffon.sftpAction.closure()
	            } else
	            {
	        		logger.debug("defaulting to shell ${model.settings.initialView}")
	            	app.views.Sshiffon.terminalAction.closure()
	            }
	            
            } catch (Exception e)
            {
                logger.warn("Connection Exception ",e)
            	view.statusMessage.text = e.message
            	view.loadingLabel.visible = false
            	view.retryButton.visible = true
            	view.quitButton.visible = true
                return false
            }
		}
        return true
    }  

    private void openTermGroup()
    {
    	view.doOutside {
	    	def mvcId = model.mvcId + '_term'
	    	def termGroup = buildMVCGroup('Term',
	           mvcId,
	    	    parentController: this, mvcId : mvcId, conn: model.conn,
	    	    session : model.session,
	    	    settings : model.settings,
	    	    savedName : model.savedName
	    	    )
	    	doLater {
	    		view.terminalCard.add(termGroup.view.terminalPanel, "grow")
		    	if(termGroup.controller.start())
		    	{
		    		model.termGroup = termGroup
		    	} else {
		    		
		    		model.termGroup = null
		    		destroyMVCGroup(mvcId)
		    	}
	    	}
    	}
    }

    private void openSftpGroups()
    {
    	openLocalGroup()
    	openRemoteGroup()

    }
    private void openLocalGroup()
    {
    	def mvcId = model.mvcId + '_local'
        def localGroup = buildMVCGroup('LocalFileViewer',
           mvcId, parentController: this, mvcId : mvcId )

        view.localViewHolderPanel.add(localGroup.view.mainPanel, "grow" )
        
        if(localGroup.controller.start())
	    	{
	    		model.localGroup = localGroup
	            view.doLater {
	    			localCards.layout.show( localCards, "loaded" )
	            }
	    	} else {
	    		model.localGroup = null
	    		destroyMVCGroup(mvcId)
	    	}
    }

    private void openRemoteGroup()
    {
    	def mvcId = model.mvcId + '_remote'
        def remoteGroup = buildMVCGroup('RemoteFileViewer',
                mvcId, parentController: this, mvcId : mvcId )

         view.remoteViewHolderPanel.add(remoteGroup.view.mainPanel, "grow" )
         if(remoteGroup.controller.start())
 	     {
 	    		model.remoteGroup = remoteGroup
	            view.doLater {
	    			remoteCards.layout.show( remoteCards, "loaded" )
	            }
 	     } else {
 	    		model.remoteGroup = null
 	    		destroyMVCGroup(mvcId)
 	     }
    }


    def quit = { evt = null ->
    	if(close())
    	{
    		logger.debug("quitting connection ")
    		if(model.session!=null)
    		{
    			model.session.disconnect();
    		}
	    	
	    	if(model.termGroup!=null)
	    	{
	    		model.termGroup.model.connector.quit();
	    		destroyMVCGroup("${model.mvcId}_term");
	    	}
	    	if(model.localGroup!=null)
	    	{
	    		try {
	    			model.localGroup.controller.quit()
	    		} catch(Exception e)
	    		{
	    			logger.warn("error destroying local group",e)
	    		}
	    	}
	    	if(model.remoteGroup!=null)
	    	{
	    		try {
	    			model.remoteGroup.controller.quit()
	    		} catch(Exception e)
	    		{
	    			logger.warn("error destroying remote group",e)
	    		}
	    	}
	    	logger.debug("quitted all subgroups")
	    	try {
	    		destroyMVCGroup(model.mvcId)
	    	} catch (Exception e)
	    	{
	    		logger.debug("error quitting ConnectionGroup")
	    	}
    	} else {
    		logger.debug("unable to quit connection")
    	}
    }
    

    /** 
     * Called when the document is closed. 
     */  
    boolean close() { 
    	
        if (model.isDirty) {  
            switch (JOptionPane.showConfirmDialog(app.appFrames[0],   
                    "Save changes to '${model.savedName}'?", "Example",   
                    JOptionPane.YES_NO_CANCEL_OPTION)){  
                case JOptionPane.YES_OPTION: return save()  
                case JOptionPane.NO_OPTION: return true  
                case JOptionPane.CANCEL_OPTION: return false  
            }  
        }  
        
        return true  
    }  

    void initialiseShell()
    {
    	if(!initialisedShell)
    	{
    		initialisedShell=true
    		openTermGroup()
    	}
    }

    void initialiseSftp()
    {
    	
    	if(!initialisedSftp)
    	{
    		logger.debug('initialising sftp')
    		initialisedSftp=true
    		openSftpGroups()
    	} else {
    		//logger.debug('sftp already initialised')
    	}
    }

    void untunnel(String item)
    {
        if(item != null)
        {
            def (lp , rh, rp) = item.split(':')
            logger.info("unbinding port ${lp}")
            model.session.delPortForwardingL(Integer.parseInt(lp))
        }
    }

    void untunnel(int port)
    {
        model.session.delPortForwardingL(port)
    }
    
    List<Map<String,?>> getLoadedTunnels() {
    	def loadedTunnels = []
        def pf = model.session.getPortForwardingL()

        for(String pfi : pf)
        {
            def (lp , rh, rp) = pfi.split(':')
            loadedTunnels.add( [ localPort:lp, remoteHost:rh, remotePort:rp ] )
        }
    	return loadedTunnels
    }
    
    void tunnel(String localPort, String remoteHost, String remotePort)
    {
        logger.debug("binding port ${localPort} onto tunnel -> ${remoteHost}:${remotePort}")
        try {
            model.session.setPortForwardingL(Integer.parseInt(localPort), remoteHost, Integer.parseInt(remotePort))
        } catch (Exception e) {
            logger.error("Failed to bind tunnel", e)
            model.settings.tunnels?.each({if(it.localPort?.equals(localPort) && it.remotePort.equals(remotePort) && it.remoteHost.equals(remoteHost)) { it.enabled=false }})
        }

    }

    void setDisableOnly(item)
	{
    	model.selectedCard= item
    	app.controllers.Sshiffon.setDisableOnly(item)
	}

}